package mint.modules.generator;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import org.antlr.runtime.tree.Tree;

import mint.modules.generator.expression.ExprNode;
import mint.modules.generator.expression.Expression;
import mint.modules.generator.expression.ExpressionType;
import mint.modules.type.Type;

public class ReturnStmtNode extends Scope implements MintNode {
	private Expression expr;	
	private int line;
	private List<String> errors;
	private Type returnType;

	public ReturnStmtNode(Scope theParent, Tree returnTree) {
		super(theParent, theParent.containerClass);
		
		if (returnTree.getChildCount() > 0)
			expr = new ExprNode(theParent, ExpressionType.Right, returnTree.getChild(0));
		else
			expr = null;
		line = returnTree.getLine();
		errors = new ArrayList<String>();
		returnType = Type.voidType;
	}

	@Override
	public void testSemantic() {
		//Encontrar al metodo o constructor padre
		Scope scope = getParent();		
		
		while (!(scope instanceof MethodDeclarationNode || scope instanceof ConstructorDeclarationNode))
		{
			scope = scope.getParent();
		}
		
		if (scope instanceof MethodDeclarationNode)
		{
			returnType = ((MethodDeclarationNode) scope).getType();
			
		} else if (scope instanceof ConstructorDeclarationNode)
		{
			returnType = Type.voidType;
			
		}
		
		if (expr != null)
		{
			if (returnType.equals(Type.voidType))
				errors.add(line + ": unexpected expression in return statement");
			else
			{
				expr.testSemantic();
				if (returnType.equals(Type.floatType))
				{
					if (!(expr.getType().equals(Type.intType) || expr.getType().equals(Type.floatType)))
						errors.add(line + ": return statement expected type " + returnType.getCompleteName()
								+ " but received" + expr.getType().getCompleteName());
				} else 	if (!expr.getType().equals(returnType))
					if(!expr.getType().equals(Type.objectNullType))
						errors.add(line + ": return statement expected type " + returnType.getCompleteName()
							+ " but received" + expr.getType().getCompleteName());
			}
		} else
		{
			if (!returnType.equals(Type.voidType))
				errors.add(line + ": expected expression in return statement from type " + returnType.getName());
		}
	}

	@Override
	public List<String> getSemanticErrors() {
		if (expr != null)
			errors.addAll(expr.getSemanticErrors());
		return errors;
	}

	@Override
	public void emit(Formatter output) {
		if (expr != null)
		{
			expr.emit(output);
			if (returnType.equals(Type.floatType) && expr.getType().equals(Type.intType))
				output.format("i2f\n");
			if (returnType.equals(Type.intType) || returnType.equals(Type.booleanType))
				output.format("ireturn\n");
			else if (returnType.equals(Type.floatType))
				output.format("freturn\n");
			else
				output.format("areturn\n");				
		}
		else
			output.format("return\n");
		
	}

	@Override
	public int getLine() {
		return line;
	}

	@Override
	public void printSymbolTable(Formatter output, int tabSize) {}

}
